package com.github.cyf.config;

import com.github.cyf.common.model.Rs;
import org.springframework.core.annotation.Order;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.stream.Collectors;

/**
 * @author chenyifan
 * @create 2024-05-03 10:18
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * Validator 校验框架返回的错误提示太臃肿了，不便于阅读，为了方便前端提示，我们需要将其简化一下。
     * @param e
     * @return
     */
    @ExceptionHandler(value = {
            MethodArgumentNotValidException.class, BindException.class, ValidationException.class
    })
    public Rs handleValidatedException(Exception e) {
        e.printStackTrace();
        if (e instanceof MethodArgumentNotValidException) {
            // 在处理控制器方法的入参时，使用了@Valid注解对方法参数进行验证，但参数对象未能通过验证的情况。
            MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
            String msg = ex.getBindingResult().getAllErrors().stream()
                    .map(ObjectError::getDefaultMessage)
                    .collect(Collectors.joining("; "));
            return Rs.error(msg);
        } else if (e instanceof ConstraintViolationException) {
            // 当使用了注解来定义验证规则（如@NotNull, @Size, @Min, @Max等），
            // 并且在进行验证时，对象的属性值不满足这些约束条件，就会抛出此异常。
            // 它包含了关于哪些约束失败以及失败的具体原因的详细信息。
            ConstraintViolationException ex = (ConstraintViolationException) e;
            String msg = ex.getConstraintViolations().stream()
                    .map(ConstraintViolation::getMessage)
                    .collect(Collectors.joining("; "));
            return Rs.error(msg);
        } else {
            // 用于处理表单提交或请求参数绑定到命令对象或模型属性时发生的验证错误。
            BindException ex = (BindException) e;
            String msg = ex.getAllErrors().stream()
                    .map(ObjectError::getDefaultMessage)
                    .collect(Collectors.joining("; "));
            return Rs.error(msg);
        }
    }
}
